机器学习工程师纳米学位

强化学习

项目 4: 训练智能出租车学会驾驶

欢迎来到机器学习工程师纳米学位的第四个项目!在这个notebook文件中,模板代码已经提供给你,有助于你对智能出租车的分析和实现学习算法。你无须改动已包含的代码,除非另有要求。 你需要回答notebook文件中给出的与项目或可视化相关的问题。每一个你要回答的问题前都会冠以'问题 X'。仔细阅读每个问题,并在后面'回答'文本框内给出完整的回答。你提交的项目会根据你对于每个问题的回答以及提交的agent.py的实现来进行评分。

提示: Code 和 Markdown 单元格可通过 Shift + Enter 快捷键来执行。此外,Markdown可以通过双击进入编辑模式。


开始

在这个项目中,你将构建一个优化的Q-Learning驾驶代理程序,它会操纵智能出租车 通过它的周边环境到达目的地。因为人们期望智能出租车要将乘客从一个地方载到另一个地方,驾驶代理程序会以两个非常重要的指标来评价:安全性可靠性。驾驶代理程序在红灯亮时仍然让智能出租车行驶往目的地或者勉强避开事故会被认为是不安全的。类似的,驾驶代理程序频繁地不能适时地到达目的地会被认为不可靠。最大化驾驶代理程序的安全性可靠性保证了智能出租车会在交通行业获得长期的地位。

安全性可靠性用字母等级来评估,如下:

等级 安全性 可靠性
A+ 代理程序没有任何妨害交通的行为,
并且总是能选择正确的行动。
代理程序在合理时间内到达目的地的次数
占行驶次数的100%。
A 代理程序有很少的轻微妨害交通的行为,
如绿灯时未能移动。
代理程序在合理时间内到达目的地的次数
占行驶次数的90%。
B 代理程序频繁地有轻微妨害交通行为,
如绿灯时未能移动。
代理程序在合理时间内到达目的地的次数
占行驶次数的80%。
C 代理程序有至少一次重大的妨害交通行为,
如闯红灯。
代理程序在合理时间内到达目的地的次数
占行驶次数的70%。
D 代理程序造成了至少一次轻微事故,
如绿灯时在对面有车辆情况下左转。
代理程序在合理时间内到达目的地的次数
占行驶次数的60%。
F 代理程序造成了至少一次重大事故,
如有交叉车流时闯红灯。
代理程序在合理时间内到达目的地的次数
未能达到行驶次数的60%。

为了协助评估这些重要的指标,你会需要加载可视化模块的代码,会在之后的项目中用到。运行下面的代码格来导入这个代码,你的分析中会需要它。

In [2]:
# 检查你的Python版本
from sys import version_info
if version_info.major != 2 and version_info.minor != 7:
    raise Exception('请使用Python 2.7来完成此项目')
In [3]:
# Import the visualization code
import visuals as vs

# Pretty display for notebooks
%matplotlib inline

# 开启 notebook 对 retina 屏幕的支持
%config InlineBackend.figure_format = 'retina'

了解世界

在开始实现你的驾驶代理程序前,首先需要了解智能出租车和驾驶代理程序运行的这个世界(环境)。构建自我学习的代理程序重要的组成部分之一就是了解代理程序的特征,包括代理程序如何运作。原样直接运行agent.py代理程序的代码,不需要做任何额外的修改。让结果模拟运行一段时间,以观察各个不同的工作模块。注意在可视化模拟程序(如果启用了),白色车辆就是智能出租车

问题 1

用几句话,描述在运行默认的agent.py代理程序中,你在模拟程序里观察到了什么。一些你可以考虑的情况:

  • 在模拟过程中,智能出租车究竟移动了吗?
  • 驾驶代理程序获得了什么样的奖励?
  • 交通灯的颜色改变是如何影响奖励的?

提示: 从顶层的/smartcab/目录(这个notebook所在的地方),运行命令

'python smartcab/agent.py'

回答:

  • 运行代码之后,观察模拟窗口之后发现白色的智能出租车并没有移动。
  • 在模拟的过程中,驾驶代理程序即获得了正的奖励也获得了负的奖励。当交通灯是红色的时候,获得的是正的奖励,当交通灯变成绿色时得到既有负的奖励也有正的奖励
  • 这是因为车一直处在停着的状态,当是红灯时它遵守了交通规则因此得到了正的奖励;当时绿灯时,车本来应该要走但它却没有走,因此得到的是负的奖励,绿灯时有时也会得到正的奖励这个还不是太清楚。

理解代码

除了要了解世界之外,还需要理解掌管世界、模拟程序等等如何运作的代码本身。如果一点也不去探索一下“隐藏”的器件,就试着去创建一个驾驶代理程序会很难。在顶层的/smartcab/的目录下,有两个文件夹:/logs/ (之后会用到)和/smartcab/。打开/smartcab/文件夹,探索每个下面的Python文件,然后回答下面的问题。

问题 2

  • agent.py Python文件里,选择 3 个可以设定的 flag,并描述他们如何改变模拟程序的。
  • environment.py Python文件里,当代理程序执行一个行动时,调用哪个Environment类的函数?
  • simulator.py Python 文件里,'render_text()'函数和'render()'函数之间的区别是什么?
  • planner.py Python文件里,'next_waypoint() 函数会先考虑南北方向还是东西方向?

回答:

  1. 选择如下三个可以设定的 flag
    • self.learning 表示是否使用 Q-learning 进行学习
    • verbose(environment.py) 表示在模拟时是否输出附加信息,设置为 True 可以方便调试
    • enforce_deadline 将此标志设定为True来强制驾驶代理程序捕获它是否在合理时间内到达目的地。
  2. 当代理程序执行一个动作时,调用的是act()这个函数。
  3. render_text()函数和render()函数之间的主要区别在于,render_text()是以non-GUI的形式运行,而render()是以GUI的形式运行。在开始运行项目的过程中就可以看到,当 pygame 没有正确安装的时候,程序是以non-GUI形式运行,当 pygame 正确安装之后,就会出现出租车的图形模拟程序。
  4. next_waypoint() 中先考虑东西方向,然后再考虑南北方向

【参考】 本文第1.6.1节 Q-learning 模拟结果


实现一个基本的驾驶代理程序

创建一个优化Q-Learning的驾驶代理程序的第一步,是让代理程序确实地执行有效的行动。在这个情况下,一个有效的行动是None(不做任何行动)、'Left'(左转)、'Right'(右转)或者'Forward'(前进)。作为你的第一个实现,到'choose_action()'代理程序函数,使驾驶代理程序随机选择其中的一个动作。注意你会访问到几个类的成员变量,它们有助于你编写这个功能,比如'self.learning''self.valid_actions'。实现后,运行几次代理程序文件和模拟程序来确认你的驾驶代理程序每步都执行随机的动作。

基本代理程序模拟结果

要从最初的模拟程序获得结果,你需要调整下面的标志:

  • 'enforce_deadline' - 将此标志设定为True来强制驾驶代理程序捕获它是否在合理时间内到达目的地。environment.py - set_primary_agent(False)
  • 'update_delay' - 将此标志设定为较小数值(比如0.01)来减少每次试验中每步之间的时间。Simulator - init(2.0)
  • 'log_metrics' - 将此标志设定为True将模拟结果记录为在/logs/目录下的.csv文件。Simulator - init(False)
  • 'n_test' - 将此标志设定为'10'则执行10次测试试验。Simulator - run(0)

可选的,你还可以通过将'display'标志设定为False来禁用可视化模拟(可以使得试验跑得更快)。调试时,设定的标志会返回到他们的默认设定。重要的是要理解每个标志以及它们如何影响到模拟。

你成功完成了最初的模拟后(有20个训练试验和10个测试试验),运行下面的代码单元格来使结果可视化。注意运行同样的模拟时,日志文件会被覆写,所以留意被载入的日志文件!在 projects/smartcab 下运行 agent.py 文件。

In [10]:
# Load the 'sim_no-learning' log file from the initial simulation results
vs.plot_trials('sim_no-learning.csv')

问题 3

利用上面的从你初始模拟中得到的可视化结果,给出关于驾驶代理程序的分析和若干观察。确保对于可视化结果上的每个面板你至少给出一条观察结果。你可以考虑的一些情况:

  • 驾驶代理程序多频繁地做出不良决策?有多少不良决策造成了事故?
  • 假定代理程序是随机驾驶,那么可靠率是否合理?
  • 代理程序对于它的行动会获得什么样的奖励?奖励是否表明了它收到严重的惩罚?
  • 随着试验数增加,结果输出是否有重大变化?
  • 这个智能出租车对于乘客来说,会被人为是安全的且/或可靠的吗?为什么或者为什么不?

答案:

  • 观察第一个图可以看到,总的不良决策率在0.3801 ~ 0.4277之间,不良决策造成的大小事故在0.095上下。
  • 若假定代理程序是随机驾驶的,那么从第三张图看到20%以下的可靠率还是比较合理的,毕竟是随机作出的决策。
  • 代理程序作出正确的行动会得到正的奖励,错的行动会得到负的奖励。从第一张图的 Total Bad Actions 曲线与第二张图的每个动作的奖励曲线可以看出,两者的走势是相反的,可知当错误越严重受到的惩罚也就越严重。
  • 从上面的输出结果看到,随着试验次数的增加输出结果并没有发生重大的变化。
  • 这个只能出租车对于乘客来说是及其不安全和可靠的,因此从上图的输出结果可以看到智能出租车的安全性与可靠性评分是 F,从安全性与可靠性等级表中可知 F 是最低一级的。

通知驾驶代理程序

创建一个优化Q-Learning的驾驶代理程序的第二步,是定义一系列代理程序会在环境中发生的状态。根据输入、感知数据和驾驶代理程序可用的变量,可以为代理程序定义一系列状态,使它最终可以学习在一个状态下它需要执行哪个动作。对于每个状态的'如果这个处于这个状态就那个行动'的状况称为策略,就是最终驾驶代理程序要学习的。没有定义状态,驾驶代理程序就不会明白哪个动作是最优的——或者甚至不会明白它要关注哪个环境变量和条件!

识别状态

查看'build_state()'代理程序函数,它显示驾驶代理函数可以从环境中获得下列数据:

  • 'waypoint'智能出租车去向目的地应该行驶的方向,它是智能出租车车头方向的相对值。
  • 'inputs'智能出租车的感知器数据。它包括
    • 'light',交通灯颜色。
    • 'left'智能出租车左侧车辆的目的方向。如果没有车辆,则返回None
    • 'right'智能出租车右侧车辆的目的方向。如果没有车辆,则返回None
    • 'oncoming'智能出租车交叉方向车辆的目的方向。如果没有车辆,则返回None
  • 'deadline'智能出租车在时间之内到达目的地还所需的剩余动作数目。

问题 4

代理程序的哪些可用特征与学习安全性效率相关性最高?你为什么认为这些特征适合在环境中对智能出租车建模?如果你没有选择某些特征,放弃他们的原因是什么?

回答:

代理程序的'light''left''oncoming''waypoint' 特征与学习安全性与效率相关性最高。

  • 'waypoint' 车辆只有知道应该形式的方向,才可以正确的到达目的地
  • 'light' 知道了交通信号灯的状态,才可以知道何时可以行车
  • 'left''oncoming' 这两个则表明了此时应该怎么行车
  • 'right' 多数情况下是不需要此特征,但为了防止出现其他车违背交通规则的情况,且为了增加车辆的安全性把此特征考虑在内

放弃'deadline',因为增加'deadline'会扩大整个状态空间,且会增加更多计算量让计算时间更长,让算法的效率变的更低。而且此题目的起点、终点不停改变,这对于代理程序泛化并没有特别大的帮助。

定义状态空间

当定义一系列代理程序会处于的状态,必需考虑状态空间的大小。就是说,如果你期望驾驶代理程序针对每个状态都学习一个策略,你会需要对于每一个代理状态都有一个最优的动作。如果所有可能状态的数量非常大,最后会变成这样的状况,驾驶代理程序对于某些状态学不到如何行动,会导致未学习过的决策。例如,考虑用下面的特征定义智能出租车的状态的情况:

('is_raining', 'is_foggy', 'is_red_light', 'turn_left', 'no_traffic', 'previous_turn_left', 'time_of_day'). 发生如(False, True, True, True, False, False, '3AM')的状态的频次如何?没有近乎无限数量的训练,很怀疑代理程序会学到一个合适的动作!

问题 5

如果用你在问题4中选择的特征来定义一个状态,状态空间的大小是多少?假定你了解环境以及它是如何模拟的,你觉得经过合理数量的训练之后,代理驾驶能学到一个较好的策略吗?(遇见绝大部分状态都能作出正确决策。) 提示: 考虑特征组合来计算状态的总数!

回答:

问题4中一共选择了4个特征,这四个特征以及可能对应的状态为:

  • 'light' 可能的值为:greenred 2个值
  • 'waypoint' 可能的值为:leftrightforward 3个值
  • 'left' 可能的值为:Noneleftrightforward 4个值
  • 'oncoming' 可能的值为:Noneleftrightforward 4个值
  • 'right' 可能的值为:Noneleftrightforward 4个值

虽然'waypoint'('left', 'right', 'forward', None) 四个值,但 None 值表明已经在目的地了不需要执行任何动作,因此此处舍弃 None 值。因此可能的状态空间大小为2×3×4×4×4=384,状态空间大小为384。

由上面的计算可以看到状态空间为384,在每一个状态下又有4种可以选择的动作,那么状态空间与动作的可能组合就为 384×4 = 1536个。即如果每次训练都遇到一个新的组合,至少需要1500此训练,考虑到又可能在几次训练之后才能得到一个比较好的值,那么训练的次数至少在4500次。我觉着这个并不是一个特别大的数字,因此代理程序应该可以学习到较好的策略。

为什么我们这么强调对相同最大值的 action 的选择要随机呢?

当代理程序刚开始运行的时候,此时 Qtable 还是空,即此时遇到的每个状态可选的动作值都是0,即此时有四个相同的最大值,而如果此时不随机的在四个最大值中选择一个,而是只固定的选择第一个,那么就无法得到最好的决策。

更新驾驶代理程序的状态

要完成你的第二个实现,去到'build_state()'代理程序函数。根据你在问题4给出的判断,你现在要将'state'变量设定为包含所有Q-Learning所需特征的元组。确认你的驾驶代理程序通过运行代理程序文件和模拟会更新它的状态,注意状态是否显示了。如果用了可视化模拟,确认更新的状态和在模拟程序里看到的一致。

注意: 观察时记住重置模拟程序的标志到默认设定!


实现Q-Learning驾驶代理程序

创建一个优化Q-Learning的驾驶代理程序的第三步,是开始实现Q-Learning自身的功能。Q-Learning的概念相当直接:每个访问的状态,为所有可用的状态-行动配对在Q-table里创建一条记录。然后,当代理程序遇到一个状态并执行了一个动作,基于获得的奖励和设定的相互的更新规则,来更新关联的状态-动作配对的Q-value。当然,Q-Learning还带来其他的收益,如此我们可以让代理程序根据每个可能的状态-动作配对的Q-values,来为每个状态选择最佳动作。在这个项目里,你会实现一个衰减 $\epsilon$ -贪心 的Q-learning算法,不含折扣因子。遵从每个代理程序函数的TODO下的实现指导。

注意代理程序的属性self.Q是一个字典:这就是Q-table的构成。每个状态是self.Q字典的键,每个值是另一个字典,包含了actionQ-value。这里是个样例:

{ 'state-1': { 
    'action-1' : Qvalue-1,
    'action-2' : Qvalue-2,
     ...
   },
  'state-2': {
    'action-1' : Qvalue-1,
     ...
   },
   ...
}

此外,注意你要求利用一个衰减$\epsilon$(探索)因子。因此,随着试验的增加,$\epsilon$会向0减小。这是因为,代理程序会从它的行为中学习,然后根据习得的行为行动。而且当$\epsilon$达到特定阈值后(默认阈值为0.01),代理程序被以它所学到的东西来作检测。作为初始的Q-Learning实现,你将实现一个线性衰减$\epsilon$的函数。

Q-Learning模拟结果

要从最初的Q-learning程序获得结果,你需要调整下面的标志和设置:

  • 'enforce_deadline' - 将此标志设定为True来强制驾驶代理程序捕获它是否在合理时间内到达目的地。
  • 'update_delay' - 将此标志设定为较小数值(比如0.01)来减少每次试验中每步之间的时间。
  • 'log_metrics' - 将此标志设定为True将模拟结果记录为在/logs/目录下的.csv文件,Q-table存为.txt文件。
  • 'n_test' - 将此标志设定为'10'则执行10次测试试验。
  • 'learning' - 将此标志设定为'True'来告诉驾驶代理使用你的Q-Learning实现。

此外,使用下面的$\epsilon$衰减函数:

$$ \epsilon_{t+1} = \epsilon_{t} - 0.05, \hspace{10px}\textrm{for trial number } t$$

如果你在实施时遇到困难,尝试把'verbose'标志设为True来调试。调试时,在这里设定的标志会返回到它们的默认设定。重要的是你要理解每个标志做什么并且解释它们怎么影响模拟!

当你成功完成初始的Q-Learning模拟程序后,运行下面代码单元格来使结果可视化。注意当相同的模拟运行时,log文件会被覆写,所以要留意载入的log文件!

In [5]:
# Load the 'sim_default-learning' file from the default Q-Learning simulation
vs.plot_trials('sim_default-learning.csv')

问题 6

利用上面的从你默认的Q-Learning模拟中得到的可视化结果,像在问题3那样,给出关于驾驶代理程序的分析和若干观察。注意模拟程序应该也产生了Q-table存在一个文本文件中,可以帮到你观察代理程序的算法。你可以考虑的一些情况:

  • 有没有观察到基本驾驶代理程序和默认的Q-Learning代理程序的相似之处?
  • 在测试之前驾驶代理大约需要做多少训练试验?在给定的$\epsilon$ 容忍度下,这个数字是否合理?
  • 你实现的$\epsilon$(探索因子)衰减函数是否准确地在参数面板中显示?
  • 随着试验数增加,不良动作的数目是否减少?平均奖励是否增加?
  • 与初始的驾驶代理程序相比,安全性和可靠性评分怎样?

回答:

  • 都共同拥有三幅相同的图,默认的Q-Learning多了因子图。但相同的三幅图的走势并不一样,Bad Actions 图之前的走势是上升或者保持不变,而默认的Q-Learning则是在持续下降;奖励图之前的趋势是下降,现在则是在上升;可靠率也是类似情况。
  • 在之前驾驶代理做了20次训练,而在默认的Q-Learning下 ϵ 的衰减为 0.05 每次训练,20次自后 ϵ 的值将为了 0 ,小于了容忍度 0.05 ,因此是合理的。
  • 通过观察可以看到是正确的在参数面板中显示了image
  • 不良动作随着试验次数的增加而减少,平均奖励会随着试验次数的增加而增加
  • 从上述输出的结果可以看到得到的平分是一样的,不知道这个评分是否正确

改进Q-Learning驾驶代理程序

创建一个优化Q-Learning的驾驶代理程序的第三步,是执行优化!现在Q-Learning算法已经实现并且驾驶代理程序已经成功学习了,需要调整设定、调节参数让驾驶代理程序学习安全性效率。通常这一步需要很多试验和错误,因为某些设定必定会造成更糟糕的学习。要记住的一件事是学习的行为本身和需要的时间:理论上,我们可以允许代理程序用非常非常长的时间来学习;然而,Q-Learning另一个目的是将没有习得行为的试验试验变为有习得行为的行动。例如,训练中总让代理程序执行随机动作(如果$\epsilon = 1$并且永不衰减)当然可以使它学习,但是不会让它行动。当改进你的Q-Learning实现时,要考虑做一个特定的调整的意义,以及它是否逻辑上是否合理。

改进Q-Learning的模拟结果

要从最初的Q-learning程序获得结果,你需要调整下面的标志和设置:

  • 'enforce_deadline' - 将此标志设定为True来强制驾驶代理程序捕获它是否在合理时间内到达目的地。
  • 'update_delay' - 将此标志设定为较小数值(比如0.01)来减少每次试验中每步之间的时间。
  • 'log_metrics' - 将此标志设定为True将模拟结果记录为在/logs/目录下的.csv文件,Q-table存为.txt文件。
  • 'learning' - 将此标志设定为'True'来告诉驾驶代理使用你的Q-Learning实现。
  • 'optimized' - 将此标志设定为'True'来告诉驾驶代理你在执行一个优化版本的Q-Learning实现。

优化Q-Learning代理程序可以调整的额外的标志:

  • 'n_test' - 将此标志设定为某个正数(之前是10)来执行那么多次测试试验。
  • 'alpha' - 将此标志设定为0 - 1之间的实数来调整Q-Learning算法的学习率。
  • 'epsilon' - 将此标志设定为0 - 1之间的实数来调整Q-Learning算法的起始探索因子。
  • 'tolerance' - 将此标志设定为某个较小的大于0的值(默认是0.05)来设定测试的epsilon阈值。

此外,使用一个你选择的$\epsilon$ (探索因子)衰减函数。注意无论你用哪个函数,一定要以合理的速率衰减'tolerance'。Q-Learning代理程序到此才可以开始测试。某个衰减函数的例子($t$是试验的数目):

$$ \epsilon = a^t, \textrm{for } 0 < a < 1 \hspace{50px}\epsilon = \frac{1}{t^2}\hspace{50px}\epsilon = e^{-at}, \textrm{for } 0 < a < 1 \hspace{50px} \epsilon = \cos(at), \textrm{for } 0 < a < 1$$

如果你想的话,你也可以使用$\alpha$ (学习率) 的衰减函数,当然这通常比较少见。如果你这么做了,确保它满足不等式$0 \leq \alpha \leq 1$。 如果你在实施时遇到困难,尝试把'verbose'标志设为True来调试。调试时,在这里设定的标志会返回到它们的默认设定。重要的是你要理解每个标志做什么并且解释它们怎么影响模拟!

当你成功完成初始的Q-Learning模拟程序后,运行下面代码单元格来使结果可视化,请注意为了达到项目要求你需要在安全性和可靠性上获得至少都为A的评分。注意当相同的模拟运行时,log文件会被覆写,所以要留意载入的log文件!

In [16]:
# Load the 'sim_improved-learning' file from the improved Q-Learning simulation
vs.plot_trials('sim_improved-learning.csv')
print("epsilon = 1.0/self.t**2, alpha=0.5, tolerance=0.0001, trial=100, n_test=100")
epsilon = 1.0/self.t**2, alpha=0.5, tolerance=0.0001, trial=100, n_test=100
In [17]:
# Load the 'sim_improved-learning' file from the improved Q-Learning simulation
vs.plot_trials('sim_improved-learning.csv')
print("epsilon = 1.0/self.t**2, alpha=0.5, tolerance=0.0000253, trial=200, n_test=100")
epsilon = 1.0/self.t**2, alpha=0.5, tolerance=0.0000253, trial=200, n_test=100
In [27]:
# Load the 'sim_improved-learning' file from the improved Q-Learning simulation
vs.plot_trials('sim_improved-learning.csv')
print("epsilon = 1.0/self.t**2, alpha=0.5, tolerance=0.0000004, trial=1500, n_test=100")
epsilon = 1.0/self.t**2, alpha=0.5, tolerance=0.0000004, trial=1500, n_test=100
In [28]:
# Load the 'sim_improved-learning' file from the improved Q-Learning simulation
vs.plot_trials('sim_improved-learning.csv')
print("epsilon = 1.0/self.t**2, alpha=0.5, tolerance=0.0000001, trial=3000, n_test=100")
epsilon = 1.0/self.t**2, alpha=0.5, tolerance=0.0000001, trial=3000, n_test=100
In [19]:
# Load the 'sim_improved-learning' file from the improved Q-Learning simulation
vs.plot_trials('sim_improved-learning.csv')
print("epsilon = cos(0.015608*t), alpha=0.5, tolerance=0.01, trial=100, n_test=100")
epsilon = cos(0.015608*t), alpha=0.5, tolerance=0.01, trial=100, n_test=100
In [20]:
# Load the 'sim_improved-learning' file from the improved Q-Learning simulation
vs.plot_trials('sim_improved-learning.csv')
print("epsilon = cos(0.00780398*t), alpha=0.5, tolerance=0.01, trial=200, n_test=100")
epsilon = cos(0.00780398*t), alpha=0.5, tolerance=0.01, trial=200, n_test=100
In [21]:
# Load the 'sim_improved-learning' file from the improved Q-Learning simulation
vs.plot_trials('sim_improved-learning.csv')
print("epsilon = cos(0.00312159*t), alpha=0.5, tolerance=0.01, trial=500, n_test=100")
epsilon = cos(0.00312159*t), alpha=0.5, tolerance=0.01, trial=500, n_test=100
In [24]:
# Load the 'sim_improved-learning' file from the improved Q-Learning simulation
vs.plot_trials('sim_improved-learning.csv')
print("epsilon = cos(0.00312159*t), alpha=0.5, tolerance=0.01, trial=500, n_test=10")
epsilon = cos(0.00312159*t), alpha=0.5, tolerance=0.01, trial=500, n_test=10
In [22]:
# Load the 'sim_improved-learning' file from the improved Q-Learning simulation
vs.plot_trials('sim_improved-learning.csv')
print("epsilon = cos(0.0015608*t), alpha=0.5, tolerance=0.01, trial=1000, n_test=100")
epsilon = cos(0.0015608*t), alpha=0.5, tolerance=0.01, trial=1000, n_test=100
In [23]:
# Load the 'sim_improved-learning' file from the improved Q-Learning simulation
vs.plot_trials('sim_improved-learning.csv')
print("epsilon = cos(0.0015608*t), alpha=0.5, tolerance=0.05, trial=1000, n_test=100")
epsilon = cos(0.0015608*t), alpha=0.5, tolerance=0.05, trial=1000, n_test=100
In [26]:
# Load the 'sim_improved-learning' file from the improved Q-Learning simulation
vs.plot_trials('sim_improved-learning.csv')
print("epsilon = cos(0.00104053*t), alpha=0.5, tolerance=0.01, trial=1500, n_test=100")
epsilon = cos(0.00104053*t), alpha=0.5, tolerance=0.01, trial=1500, n_test=100
In [29]:
# Load the 'sim_improved-learning' file from the improved Q-Learning simulation
vs.plot_trials('sim_improved-learning.csv')
print("epsilon = cos(0.000520265*t), alpha=0.5, tolerance=0.01, trial=3000, n_test=100")
epsilon = cos(0.000520265*t), alpha=0.5, tolerance=0.01, trial=3000, n_test=100

问题7

利用上面的从你改进的Q-Learning模拟中得到的可视化结果,像在问题6那样,给出关于改进的驾驶代理程序的最终分析和观察。你需要回答的问题:

  • 使用了什么epsilon(探索因子)的衰减函数?
  • 在测试之前驾驶代理大约需要做多少训练试验?
  • 你用了什么epsilon-tolerance和alpha(学习率)值?为什么?
  • 与之前的默认Q-Learning学习器相比,这个Q-Learning学习器有多少改进?
  • 你会说Q-Learning学习器的结果表明了你的驾驶代理程序成功地学习了一个合适的策略吗?
  • 你对智能出租车的安全性和可靠性评分满意吗?

回答:

经过不同参数的测试,得到如下的结果表:

序号 衰减函数 a alpha tolerance trials n_test safety reliability
1 $$\epsilon = \frac{1}{t^2}$$ 0.5 0.001 100 100 F F
2 $$\epsilon = \frac{1}{t^2}$$ 0.5 0.0000253 200 100 F F
3 $$\epsilon = \frac{1}{t^2}$$ 0.5 0.0000004 1500 100 A+ B
4 $$\epsilon = \frac{1}{t^2}$$ 0.5 0.0000001 3000 100 A+ B
5 $$\epsilon = \cos(a*t)$$ 0.015608 0.5 0.01 100 100 F B
6 $$\epsilon = \cos(a*t)$$ 0.00780398 0.5 0.01 200 100 F A
7 $$\epsilon = \cos(a*t)$$ 0.00312159 0.5 0.01 500 100 F A
8 $$\epsilon = \cos(a*t)$$ 0.00312159 0.5 0.01 500 10 F A
9 $$\epsilon = \cos(a*t)$$ 0.0015608 0.5 0.01 1000 100 F A
10 $$\epsilon = \cos(a*t)$$ 0.0015608 0.5 0.05 1000 100 F A
11 $$\epsilon = \cos(a*t)$$ 0.00104053 0.5 0.01 1500 100 A+ A
12 $$\epsilon = \cos(a*t)$$ 0.000520265 0.5 0.01 3000 100 A+ A+
  • 使用了$$\epsilon = \cos(at), \textrm{for } 0 < a < 1 \hspace{50px}\epsilon = \frac{1}{t^2}$$ epsilon 的作用是让车能有一定的概率进行随机选择 action,随着训练次数的增加小车已经尽可能多的遇到了各种 state,因此越往后随机选择的概率应该越小,使用,使用余弦函数可以让小车在较多的训练中都可以进行随机选择,因此选择余弦函数。
  • 使用了 1500 以上的训练试验,在 1500 之前的训练得到的结果都不理想
  • 使用的 tolerance(epsilon 降到小于此值时开始进行测试) 为 0.01,因为选择的是余弦函数,且设置的 a 值为0.000520265,因此 cos(3000 * 0.000520265)<0.01;使用的 alpha 为 0.5,如果设置的过小小车只会在乎之前的reward 不会累积学习结果,这只为0.5用于平衡以前的知识和新的 reward。
  • 改进了几个参数的设定,如训练次数、tolerance 和 衰减函数
  • 因此最后的评分结果,我觉得驾驶代理程序成功地学习了一个合适的策略
  • 对于最终评分安全性为 A+、可靠性为 A+ ,这个结果很满意

定义一个最优策略

有时,对于重要的问题“我要让我的代理程序学习什么?”的答案,只是理论性的,无法具体描述。然而这里,你可以具体定义代理程序要学什么,就是美国通行权交通法案。这些法律是已知信息,你可以基于这些法律,为智能出租车进一步定义每一个状态所做的最优动作。在那种情况下,我们称这一系列最优状态-动作配对为最优策略。因此,不像那些理论性的回答,不仅通过收到的奖励(惩罚),而且纯观察,代理程序是否在“错误”地行动能很清晰地得知。如果代理程序闯了红灯,我们既看见它获得了一个负面奖励,也知道这是一个错误的行为。这可以用来帮你验证驾驶代理程序习得的策略是否正确,或只是个次优策略

问题 8

给出几个关于最优策略是什么样子的例子(用你已定义的状态)。之后,查看'sim_improved-learning.txt'文本文件,看你的改进的Q-Learning算法的结果。每个从模拟中纪录的状态,对于给定的状态,策略(得分最高的动作)是否正确?是否对于有些状态,有策略不同于预期的最优策略?给出一个状态和记录的状态-动作的奖励,解释为什么正是个正确的策略。

回答:

宏观最优策略即在保证安全性的前提下用最快的时间到达目的地,经过3000次以上的训练之后小车基本上把大部分可能的状态都已经遇到了,在安全性上基本上已经有了保证,可靠性则需要小车依据当前的状态作出合理的选择,以尽可能快的速度到达目的地。宏观上的最佳策略如下:

  • 遇到了红灯且下一步又是直行,那么停止不动就是最佳的策略
  • 遇到了红灯但下一步是右转,那么在左侧车非直行的前提下右转就是最佳的策略

几个策略的分析:

  1. 对于下面的一个策略

    ('forward', 'green', 'right', 'left', 'right')
    -- None : -0.15
    -- forward : 0.00
    -- right : 0.39
    -- left : 1.03

    可以看到得分最高的是 left,此时的 waypoint 是 forward。左侧的车目的地市 right,不影响小车;交叉方向和右侧车的目的分别为 left和 right,但左转和右转的的应该让直行,显然此时最佳的选择是 forward 而不是 left。选择 left 会增加到达目的地的时间,但如果考虑到其他车辆有可能违反交通规则的情况,选择 left 算是一个次优的选择。

  2. 对于下面这个策略

    ('forward', 'green', None, 'forward', None)
    -- None : -4.99
    -- forward : 2.25
    -- right : 0.81
    -- left : -20.30

    可以看到 forward 为最高得分,而此时的 waypoint 为 forward,且 light 为 green、left为 None、oncoming 为 forward,此时的最佳策略就是 forward。因为 oncoming 是 forward,若此时左转风险会非常的高,因此在此状态下 left 的得分是最低的。


选做:未来奖励 - 折扣因子 'gamma'

也许你会好奇,作为Q-Learning算法的一部分,之前要求你在实现中不要使用折扣引子'gamma'。在算法中包含未来奖励能有助于在未来状态回溯到当前状态时的反向正面奖励。本质上,如果给予驾驶代理程序执行若干动作到达不同状态的选择,包含未来奖励会是代理程序偏向可以得到更多奖励的状态。一个例子是驶向目的的驾驶代理程序:所有行动和奖励都相等,那么理论上如果到达目的地会有额外奖励,驶向目的会获得更好的奖励。然而,即使在这个项目里,驾驶代理程序也要在规定的时间里到达目的地,包含未来奖励不会有益于代理程序。实际上,如果代理程序给予多次试验学习,它甚至会给Q-value带来负面影响!

可选问题 9

在项目中有两个特点使得未来奖励在这个Q-Learning算法无效。一个特点是关于智能出租车本身,另一个是关于环境。你能指出它们是什么以及为什么未来奖励不会在这个项目中起效?

回答:

注意:当你写完了所有的代码,并且回答了所有的问题。你就可以把你的 iPython Notebook 导出成 HTML 文件。你可以在菜单栏,这样导出File -> Download as -> HTML (.html)把这个 HTML 和这个 iPython notebook 一起做为你的作业提交。